Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Assignment9+10: Parker Brown+ Leo Marlow #83

Open
wants to merge 34 commits into
base: Assignment9+10-Multithreading
Choose a base branch
from

Conversation

Pbrown34
Copy link

My partner for this assignment was @LeoMarlow

@Pbrown34 Pbrown34 force-pushed the Assignment9+10-Multithreading branch from 59d50fa to 7c0ab22 Compare December 11, 2024 05:48
Copy link

@twoody0 twoody0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instructions

  1. Implement PingProcess' public Task<PingResult> RunTaskAsync(string hostNameOrAddress)
    • First implement public void RunTaskAsync_Success() test method to test PingProcess.RunTaskAsync() using "localhost". ✔
    • Do NOT use async/await in this implementation. ✔
  2. Implement PingProcess' async public Task<PingResult> RunAsync(string hostNameOrAddress)
    • First implement the public void RunAsync_UsingTaskReturn_Success() test method to test PingProcess.RunAsync() using "localhost" without using async/await. ✔
    • Also implement the async public Task RunAsync_UsingTpl_Success() test method to test PingProcess.RunAsync() using "localhost" but this time DO using async/await. ✔
  3. Add support for an optional cancellation token to the PingProcess.RunAsync() signature. ✔
    Inside the PingProcess.RunAsync() invoke the token's ThrowIfCancellationRequested() method so an exception is thrown. ✔
    Test that, when cancelled from the test method, the exception thrown is an AggregateException ✔ with a TaskCanceledException inner exception ✔ using the test methods RunAsync_UsingTplWithCancellation_CatchAggregateExceptionWrapping ✔and RunAsync_UsingTplWithCancellation_CatchAggregateExceptionWrappingTaskCanceledException ✔ respectively.
  4. Complete/fix AND test async public Task<PingResult> RunAsync(IEnumerable<string> hostNameOrAddresses, CancellationToken cancellationToken = default) which executes ping for an array of hostNameOrAddresses (which can all be "localhost") in parallel, adding synchronization if needed. ✔
    NOTE:
    • The order of the items in the stdOutput is irrelevant and expected to be intermingled.
    • StdOutput must have all the ping output returned (no lines can be missing) even though intermingled. ❌
  5. Implement AND test public Task<int> RunLongRunningAsync(ProcessStartInfo startInfo, Action<string?>? progressOutput, Action<string?>? progressError, CancellationToken token) using Task.Factory.StartNew() and invoking RunProcessInternal with a TaskCreation value of TaskCreationOptions.LongRunning and a TaskScheduler value of TaskScheduler.Current. Returning a Task<PingResult> is also okay. ✔
    NOTE: This method does NOT use Task.Run. ✔

Extra Credit

  • Test and implement PingProcess.RunAsync(System.IProgress<T> progess) so that you can capture the output as it occurs rather than capturing the output only when the process finishes. ❌✔

Fundamentals

  • Place all shared project properties into a Directory.Build.Props file.
  • Place all shared project items into a Directory.Build.targets file.
  • Ensure nullable reference types is enabled ✔
  • Ensure that you turn on code analysis for all projects(EnableNETAnalyzers) ✔
  • Set LangVersion and the TargetFramework to the latest released versions available (preview versions optional) ✔
  • and enabled .NET analyzers for both projects ✔
  • For this assignment, consider using Assert.AreEqual<T>() (the generic version) ✔
  • All of the above should be unit tested ✔
  • Choose simplicity over complexity ✔

Overall

You guys did a good job! What I would suggest working on is ensuring that you aren't using Task.Run since it explicitly states not to. Then I would try to get the standard output working. I'll update my PR and change the ❌'s to ✔'s when you fix it :)

}
return new PingResult(process.ExitCode, stdOutput);
}
public Task<PingResult> RunTaskAsync(string hostNameOrAddress, CancellationToken cancellationToken = default)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You shouldn't need the second parameter CancellationToken cancellationToken = default

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed


Process process = RunProcessInternal(startInfo, updateStdOutput, progressError, token);

await Task.Run(() => process.WaitForExit(), token);
Copy link

@twoody0 twoody0 Dec 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The instructions say to use Task.Factory.StartNew() and use TaskCreationOptions.LongRunning, so just make sure to replace Task.Run with Task.Factory.StartNew(). You might have to refactor this method slightly

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

}

[TestMethod]
async public Task RunAsync_UsingTpl_Success()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: White space, just move the test right one tab

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Assert.AreEqual(numbers.Count() + 1, lineCount);
}

// private readonly string PingOutputLikeExpression = @"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like you completely removed the WildCardPattern class, I think if you add it back you shouldn't have to comment out this method, and the following methods, but either way I don't blame you because of how many issues it caused me and my partner. But you will need this to verify "StdOutput must have all the ping output returned (no lines can be missing) even though intermingled." If we get it working I'll let you know.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, we got it working, this is how we formatted it:

private readonly string PingOutputLikeExpression = @"
PING * 56 data bytes
64 bytes from * (::1): icmp_seq=* ttl=* time=* ms
64 bytes from * (::1): icmp_seq=* ttl=* time=* ms
64 bytes from * (::1): icmp_seq=* ttl=* time=* ms
64 bytes from * (::1): icmp_seq=* ttl=* time=* ms

--- * ping statistics ---
* packets transmitted, * received, *% packet loss, time *ms
rtt min/avg/max/mdev = */*/*/* ms
".Trim();

I don't think there's any other way to format it than this. Just be sure to add the WildCardPattern class back and then you should be able to use AssertValidPingOutput in the tests.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe parker fixed this

{
if (ex.InnerException is TaskCanceledException)
{
throw new AggregateException(ex.InnerException);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You shouldn't need to throw a new AggregateException(ex.InnerException) here when you're already expecting the exception.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a wrapper for aggregate expression. The expected was a taskcanceledExemption which then is rewrapped

async public Task RunAsync_MultipleHostAddresses_True()
{
string[] hostNames = new string[] { "-c 4 localhost", "-c 4 localhost", "-c 4 localhost", "-c 4 localhost" };
foreach (var hostName in hostNames)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that since this is ran inside of the foreach loop, it negates the parallel execution since it processes each hostname one by one. I would suggest just getting rid of the foreach loop.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Copy link

@KennethWhite KennethWhite left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall nice work! Just a few minor cleanup issues but looks like you nailed the assignment criteria.

PingResult result = Sut.Run("-c 4 localhost");
Assert.AreEqual(0, result.ExitCode);

// AssertValidPingOutput(result);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: We want to remove unused/commented code prior to opening a PR.

{
throw new AggregateException(ex.InnerException);
}
throw ex.Flatten().InnerException ?? ex;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In addition to Tyler's comment above, when you throw the InnerException here (or ex) we will actually lose the original stack trace on the exception. We want this information to potentially debug issues and understand where the exception was first thrown, even though this is a unit test.

{
cancellationToken.ThrowIfCancellationRequested();
return Run(hostNameOrAddress);
}, cancellationToken);
}

async public Task<PingResult> RunAsync(params string[] hostNameOrAddresses)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This modifier declaration order is inconsistent from the standard. It should be:

Suggested change
async public Task<PingResult> RunAsync(params string[] hostNameOrAddresses)
public async Task<PingResult> RunAsync(params string[] hostNameOrAddresses)

await Task.WhenAll(all);
int total = all.Aggregate(0, (total, item) => total + item.Result);
return new PingResult(total, stringBuilder?.ToString());
Task<PingResult>[] tasks = hostNameOrAddresses.Select((string x) => RunAsync(x)).ToArray();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like you are failing to capture all the ping output from the processes here.

@LeoMarlow LeoMarlow force-pushed the Assignment9+10-Multithreading branch 2 times, most recently from 9686688 to 4c10012 Compare December 13, 2024 22:47
Copy link

Summary

Summary
Generated on: 12/13/2024 - 22:49:00
Coverage date: 12/13/2024 - 22:48:58
Parser: MultiReport (2x Cobertura)
Assemblies: 1
Classes: 2
Files: 1
Line coverage: 82.3% (93 of 113)
Covered lines: 93
Uncovered lines: 20
Coverable lines: 113
Total lines: 171
Branch coverage: 73.6% (28 of 38)
Covered branches: 28
Total branches: 38
Method coverage: Feature is only available for sponsors
Tag: 1072_12324188404

Coverage

Assignment - 82.3%
Name Line Branch
Assignment 82.3% 73.6%
Assignment.PingProcess 82.1% 73.6%
Assignment.PingResult 100%

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants